#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    QFile file("config.ini");
    if(!file.exists())
    {
        QSettings settings("config.ini", QSettings::IniFormat);
        settings.setValue("application", QCoreApplication::applicationFilePath());
        settings.setValue("bootloader", QCoreApplication::applicationFilePath());
        settings.setValue("offset", "");
        settings.setValue("savepath", QCoreApplication::applicationFilePath());
        settings.setValue("opendir", Qt::Unchecked);
    }

    QSettings settings("config.ini", QSettings::IniFormat);
    ui->lineEditApplicationUrl->setText(settings.value("application").toString());
    ui->lineEditBootloaderUrl->setText(settings.value("bootloader").toString());
    ui->lineEditOffsetAddress->setText(settings.value("offset").toString());
    ui->checkBoxOpenOutputDir->setCheckState((Qt::CheckState)(settings.value("opendir").toInt()));

    ui->lineEditOffsetAddress->setPlaceholderText(tr("请输入十六进制格式，例如：0X2000"));

    QRegExp regx("[0][Xx][A-Fa-f0-9]{8}");
    QRegExpValidator* validator = new QRegExpValidator(regx, ui->lineEditOffsetAddress);
    ui->lineEditOffsetAddress->setValidator(validator);

    QObject::connect(ui->btnMergeFirmware, SIGNAL(clicked(bool)), this, SLOT(slotMergeFirmware()));
    QObject::connect(ui->btnSelectApplication, SIGNAL(clicked(bool)), this, SLOT(slotSelectApplication()));
    QObject::connect(ui->btnSelectBooloader, SIGNAL(clicked(bool)), this, SLOT(slotSelectBootloader()));
}

Widget::~Widget()
{
    QSettings settings("config.ini", QSettings::IniFormat);
    settings.setValue("bootloader", ui->lineEditBootloaderUrl->text());
    settings.setValue("application", ui->lineEditApplicationUrl->text());
    settings.setValue("opendir", ui->checkBoxOpenOutputDir->checkState());
    settings.setValue("offset", ui->lineEditOffsetAddress->text());
    delete ui;
}

void Widget::slotSelectBootloader()
{
    QFileInfo fileInfo(ui->lineEditBootloaderUrl->text());
    QString filename = QFileDialog::getOpenFileName(this, tr("选择Bootloader"), fileInfo.absolutePath(), "*");
    if(filename != tr(""))
    {
        ui->lineEditBootloaderUrl->setText(filename);
    }
}

void Widget::slotSelectApplication()
{
    QFileInfo fileInfo(ui->lineEditApplicationUrl->text());
    QString filename = QFileDialog::getOpenFileName(this, tr("选择Application"), fileInfo.absolutePath(), "*");
    if(filename != tr(""))
    {
        ui->lineEditApplicationUrl->setText(filename);
    }
}

void Widget::slotMergeFirmware()
{
    quint32 offset = ui->lineEditOffsetAddress->text().toInt(nullptr, 16);
    QString bootName = ui->lineEditBootloaderUrl->text();
    QString appName  = ui->lineEditApplicationUrl->text();

    if(offset == 0 || bootName == tr("") || appName == tr(""))
    {
        QMessageBox::critical(this, tr("错误"), tr("错误，请检查下列选项是否设置：\r\n1：是否选择了bootloader？\r\n2：是否选择了application？\r\n3：是否填写了偏移地址？"), QMessageBox::Ok);
        return;
    }

    // 从配置文件中取得最后一次保存位置
    QSettings settings("config.ini", QSettings::IniFormat);
    QString lastSavePath = settings.value("savepath").toString();

    // 打开保存窗口
    QString firmwareName = QFileDialog::getSaveFileName(this, tr("保存固件"), lastSavePath, "*");

    if(firmwareName != tr(""))
    {
        // 保存最后一次保存位置
        settings.setValue("savepath", QFileInfo(firmwareName).absolutePath());

        // 打开文件
        QFile bootloader(bootName);
        QFile application(appName);
        QFile firmware(firmwareName);

        if(!bootloader.isOpen())
        {
            if(!bootloader.open(QIODevice::ReadOnly))
            {
                QMessageBox::critical(this, tr("错误"), tr("bootloader文件打开失败，请检查！"), QMessageBox::Ok);
                return;
            }
        }

        if(!application.isOpen())
        {
            if(!application.open(QIODevice::ReadOnly))
            {
                QMessageBox::critical(this, tr("错误"), tr("application文件打开失败，请检查！"), QMessageBox::Ok);
                return;
            }
        }

        if(!firmware.isOpen())
        {
            if(!firmware.open(QFile::WriteOnly))
            {
                QMessageBox::critical(this, tr("错误"), tr("合并输出固件文件名称错误，请检查！"), QMessageBox::Ok);
                return;
            }
        }

        // 将固件文件重置为0
        firmware.resize(0);

        // 合并bootloader和application
        char* buffer = new char[offset + application.size()];
        bootloader.read(&buffer[0], bootloader.size());
        application.read(&buffer[offset], application.size());
        firmware.write(buffer, offset + application.size());
        delete[] buffer;

        // 打开输出目录并定位到固件文件
        if(ui->checkBoxOpenOutputDir->isChecked())
        {
            QProcess process(this);
            QString cmd(tr("explorer /select, \"%1\"").arg(firmwareName.replace("/", "\\")));
            process.startDetached(cmd);
        }
    }
}
